/*
 * Copyright 2006-2007 S W McIlroy
 * Licensed  under the  Apache License,  Version 2.0  (the "License");
 * you may not use  this file  except in  compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed  under the  License is distributed on an "AS IS" BASIS,
 * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
 * implied.
 *
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.mockfu;

import static org.mockfu.Mocks.*;

import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Locale;

import org.testng.annotations.Test;

public class MethodReplacementTest
{

    @Test
    public void constructorReplacement()
    {
        GregorianCalendar stub = new GregorianCalendar(1940, 8, 10);

        UnitBuilder<Unit> unitBuilder = UnitBuilder.of(Unit.class);
        unitBuilder.replaceConstructor(GregorianCalendar.class, 2000, any(int.class), or(3, 4))
                .with(stub).inMethod().yearOfDragon();
        Unit unit = unitBuilder.createUnit();

        assertThat(unit.yearOfDragon(), "1940");
    }

    @Test
    public void constructorMismatch()
    {
        GregorianCalendar stub = new GregorianCalendar(1940, 8, 10);

        UnitBuilder<Unit> unitBuilder = UnitBuilder.of(Unit.class);
        unitBuilder.replaceConstructor(GregorianCalendar.class, 2000, any(int.class), or(4, 5))
                .with(stub).inMethod().yearOfDragon();
        Unit unit = unitBuilder.createUnit();

        assertThat(unit.yearOfDragon(), "2000");
    }

    @Test
    public void inMethod()
    {
        GregorianCalendar stub = new GregorianCalendar(1952, 8, 10);

        UnitBuilder<Unit> unitBuilder = UnitBuilder.of(Unit.class);
        unitBuilder.replaceConstructor(GregorianCalendar.class, any(int.class), 2, 3)
                .with(stub).inMethod().yearOfDragon();
        Unit unit = unitBuilder.createUnit();

        assertThat(unit.yearOfDragon(), "1952");
        assertThat(unit.yearOfPig(), "1995");
    }

    @Test
    public void virtualInvocation()
    {
        UnitBuilder<Unit> unitBuilder = UnitBuilder.of(Unit.class);
        unitBuilder.replaceInvocation($($(GregorianCalendar.class).get(Calendar.YEAR)))
                .with(1000).inMethod().yearOfDragon();
        Unit unit = unitBuilder.createUnit();

        assertThat(unit.yearOfDragon(), "1000");
    }

    @Test
    public void staticInvocation()
    {
        GregorianCalendar stub = new GregorianCalendar(1999, 11, 31);

        UnitBuilder<Unit> unitBuilder = UnitBuilder.of(Unit.class);
        unitBuilder.replaceInvocation($(Calendar.class, "getInstance")).with(stub).inMethod().currentYear();
        Unit unit = unitBuilder.createUnit();

        assertThat(unit.currentYear(), "1999");
    }

    @Test
    public void multipleReplacements()
    {
        GregorianCalendar stub1 = new GregorianCalendar(1951, 11, 31);
        GregorianCalendar stub2 = new GregorianCalendar(1961, 11, 31);

        UnitBuilder<Unit> unitBuilder = UnitBuilder.of(Unit.class);
        unitBuilder.replaceConstructor(GregorianCalendar.class, 1950, 2, 3).with(stub1);
        unitBuilder.replaceConstructor(GregorianCalendar.class, 1960, 2, 3).with(stub2);
        Unit unit = unitBuilder.createUnit();

        assertThat(unit.yearOf(1950), "1951");
        assertThat(unit.yearOf(1960), "1961");
    }

    protected static class Unit
    {

        public String yearOfDragon()
        {
            new GregorianCalendar(new Locale("plah"));
            Calendar c = new GregorianCalendar(2000, 2, 3);
            return "" + c.get(Calendar.YEAR);
        }

        public String yearOfPig()
        {
            Calendar c = new GregorianCalendar(1995, 2, 3);
            return "" + c.get(Calendar.YEAR);
        }

        public String currentYear()
        {
            Calendar c = Calendar.getInstance();
            return "" + c.get(Calendar.YEAR);
        }

        public String yearOf(int year)
        {
            Calendar c = new GregorianCalendar(year, 2, 3);
            return "" + c.get(Calendar.YEAR);
        }
    }
}
